﻿Imports System.Collections
Imports System.Collections.Generic
Imports System.Xml
'Imports Jayrock.Json.Conversion
Imports Pop.Api.Parser
Imports Pop.Api.Request
Imports Pop.Api.Util

Namespace Pop.Api

    ''' <summary>
    ''' 基于OAuth版的POP客户端。
    ''' </summary>
    Public Class OAuthPopClient
        Implements IPopClient

        Private Const TIME_STAMP As String = "timeStamp"
        Private Const RANDOM_VALUE As String = "randomValue"
        Private Const m_UIN As String = "uin"
        Private Const ACCESS_TOKEN As String = "accessToken"
        Private Const APPOAUTH_ID As String = "appOAuthID"
        Private Const FORMAT_XML As String = "xml"

        Private appOAuthID As String
        Private secretKey As String

        Private Shared Random As New Random
        Private webUtils As WebUtils
        Private popLogger As IPopLogger

        WriteOnly Property SetTimeout As Integer
            Set(ByVal value As Integer)
                webUtils.Timeout = value
            End Set
        End Property
        WriteOnly Property SetPopLogger As IPopLogger
            Set(ByVal value As IPopLogger)
                popLogger = value
            End Set
        End Property

        ''' <summary>
        ''' 禁用响应结果解释
        ''' </summary>
        Property DisableParser As Boolean
        ''' <summary>
        ''' 禁用日志调试功能
        ''' </summary>
        Property DisableTrace As Boolean

#Region "DefaultPopClient Constructors"

        Sub New()
            Me.New(Nothing, Nothing)
        End Sub

        Sub New(ByVal appOAuthID As String, ByVal secretKey As String)
            Me.appOAuthID = appOAuthID
            Me.secretKey = secretKey
            Me.webUtils = New WebUtils
            Me.popLogger = New DefaultPopLogger
        End Sub

#End Region

#Region "IPopClient Members"

        Public Function Execute(Of T As PopResponse)(ByVal request As IPopRequest(Of T)) As T Implements IPopClient.Execute
            Return Execute(request, Nothing, Nothing)
        End Function

        Public Function Execute(Of T As PopResponse)(ByVal request As IPopRequest(Of T), ByVal uin As String, ByVal token As String) As T Implements IPopClient.Execute
            Return Execute(request, uin, token, DateTime.Now)
        End Function

        Public Function Execute(Of T As PopResponse)(ByVal request As IPopRequest(Of T), ByVal uin As String, ByVal token As String, ByVal timestamp As Date) As T Implements IPopClient.Execute
            Return DoExecute(request, uin, token, timestamp)
        End Function

#End Region

        Private Function DoExecute(Of T As PopResponse)(ByVal request As IPopRequest(Of T), ByVal uin As String, ByVal token As String, ByVal timestamp As Date) As T
            Try
                request.Validate()
            Catch ex As PopException
                Return createErrorResponse(Of T)(ex.ErrorCode, ex.ErrorMsg, request.Format)
            End Try

            Dim txtParams As New PopDictionary(request.GetParameters)
            txtParams.Add(TIME_STAMP, timestamp)
            txtParams.Add(RANDOM_VALUE, Random.Next(10000, 100000))
            txtParams.Add(m_UIN, uin)
            txtParams.Add(ACCESS_TOKEN, token)
            txtParams.Add(APPOAUTH_ID, Me.appOAuthID)
            Dim sign As String = txtParams.GetNewSign(request.ServerUrl, secretKey)

            Dim body As String
            body = webUtils.DoGet(request.ServerUrl, txtParams, sign)

            ' 解释响应结果
            Dim rsp As T
            If DisableParser Then
                rsp = Activator.CreateInstance(Of T)()
                rsp.Body = body
            Else
                Dim tp As IPopParser(Of T)
                If request.Format = FORMAT_XML Then
                    tp = New PopXmlParser(Of T)
                Else
                    tp = New PopJsonParser(Of T)
                End If
                rsp = tp.Parse(body)
            End If

            ' 追踪错误的请求
            If Not DisableTrace Then
                rsp.ReqUrl = webUtils.BuildGetUrl(request.ServerUrl, txtParams)
                If rsp.IsError Then
                    popLogger.Warn(rsp.GetString & vbCrLf & rsp.Body)
                End If
            End If

            rsp.GetString = txtParams.GetString(rsp.ReqUrl, body)

            Return rsp
        End Function

        Private Shared Function createErrorResponse(Of T As PopResponse)(ByVal errCode As String, ByVal errMsg As String, ByVal format As String) As T
            Dim rsp As T = Activator.CreateInstance(Of T)()
            rsp.ErrCode = errCode
            rsp.ErrMsg = errMsg

            If format = FORMAT_XML Then
                Dim root As New XmlDocument()
                Dim bodyE As XmlElement = root.CreateElement("errorResponse")
                Dim codeE As XmlElement = root.CreateElement("errorCode")
                codeE.InnerText = errCode
                bodyE.AppendChild(codeE)
                Dim msgE As XmlElement = root.CreateElement("errorMessage")
                msgE.InnerText = errMsg
                bodyE.AppendChild(msgE)
                root.AppendChild(bodyE)
                rsp.Body = root.OuterXml
            Else
                Dim errObj As IDictionary(Of String, Object) = New Dictionary(Of String, Object)
                errObj.Add("errorCode", errCode)
                errObj.Add("errorMessage", errMsg)
                Dim root As IDictionary(Of String, Object) = New Dictionary(Of String, Object)
                root.Add("errorResponse", errObj)
                'rsp.Body = JsonConvert.ExportToString(root)
            End If

            Return rsp
        End Function

    End Class

End Namespace